﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

using System.Drawing;
using GaugeEngine.Graphics;
using GaugeEngine.Events;
using GaugeEngine.Process;
using GaugeEngine.Scripting;

using SlimDX;
using SlimDX.Windows;

using SlimDX.XInput;

using SlimDX.DirectSound;

namespace GaugeEngine
{
    public abstract class Game : IDisposable
    {
        protected List<GameComponent> GameComponents = new List<GameComponent>();
        protected GraphicsManager GraphicsComponent;
        private Form GameWindow = new RenderForm("GaugeEngine");
        public EventManager EventController;
        public ProcessManager ProcessController;
        protected ScriptManager m_scriptManager;

        private bool m_xboxConnected;
        private SlimDX.XInput.Controller m_xboxController1;

        public Form GameForm
        {
            get { return GameWindow; }
        }

        GameTime TotalGameTime = new GameTime();

        public Game()
        {
            //setup graphics
            GraphicsComponent = new GraphicsManager(this);
            GameWindow.Width = 800;
            GameWindow.Height = 600;
            GameWindow.ShowIcon = false;
            GameWindow.Resize += GameWindow_Resize;
            GameWindow.KeyDown += GameWindow_KeyDown;

            //setup events
            EventController = new EventManager(this);           

            //setup process
            ProcessController = new ProcessManager(this);

            //setup script
            m_scriptManager = new ScriptManager(this);
            
            //setup controller
            try
            {
                m_xboxController1 = new Controller(UserIndex.One);
                SlimDX.XInput.State s = m_xboxController1.GetState();
                m_xboxConnected = true;
            }
            catch
            {
                m_xboxConnected = false;
            }

            ContentFactory.RegisterBehaviour("sprite", Behaviours.Drawable.CreateDrawable);
            ContentFactory.RegisterBehaviour("move", Behaviours.Moveable.CreateMoveable);
        }

        void GameWindow_KeyDown(object sender, KeyEventArgs e)
        {
            EventData event_data = new EventData("KeyPress_" + e.KeyCode.ToString());
            EventController.QueueEvent(event_data);
        }

        void GameWindow_Resize(object sender, EventArgs e)
        {
            GraphicsComponent.Resize();
        }

        protected void ExitGame(EventData data)
        {
            GameForm.Close();
        }

        void GameLoop()
        {
            //check input
            if (m_xboxConnected)
            {
                if (m_xboxController1.GetState().Gamepad.Buttons.HasFlag(SlimDX.XInput.GamepadButtonFlags.Back)) EventController.QueueEvent(new EventData("XBOX_Button_Back"));
                if (m_xboxController1.GetState().Gamepad.Buttons.HasFlag(SlimDX.XInput.GamepadButtonFlags.A)) EventController.QueueEvent(new EventData("XBOX_Button_A"));
                if (m_xboxController1.GetState().Gamepad.Buttons.HasFlag(SlimDX.XInput.GamepadButtonFlags.B)) EventController.QueueEvent(new EventData("XBOX_Button_B"));
                if (m_xboxController1.GetState().Gamepad.Buttons.HasFlag(SlimDX.XInput.GamepadButtonFlags.X)) EventController.QueueEvent(new EventData("XBOX_Button_X"));
                if (m_xboxController1.GetState().Gamepad.Buttons.HasFlag(SlimDX.XInput.GamepadButtonFlags.Y)) EventController.QueueEvent(new EventData("XBOX_Button_Y"));
            }

            //run events
            EventController.Update(TotalGameTime);

            //update
            foreach (GameComponent gc in GameComponents) gc.Update(TotalGameTime);
            Update(TotalGameTime);
            GraphicsComponent.Render();
        }

        public void Run()
        {
            MessagePump.Run(GameWindow, GameLoop);
        }

        public abstract void Draw(Painter p);

        public abstract void Update(GameTime gameTime);

        public void Dispose()
        {
            GameWindow.Dispose();
            GraphicsComponent.Dispose();
            m_scriptManager.Dispose();
        }
    }
}
